package org.finesys.common.log.core.aspect;

import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.finesys.common.core.exception.BusinessException;
import org.finesys.common.core.util.SpringContextHolder;
import org.finesys.common.log.core.annotation.LogAnnotation;
import org.finesys.common.log.core.enums.BusinessStatus;
import org.finesys.common.log.event.OperateLogEvent;
import org.finesys.common.log.util.LogUtil;
import org.finesys.system.api.entity.SysLog;
import org.springframework.expression.EvaluationContext;
import org.springframework.util.StringUtils;

@Aspect
@Slf4j
public class LogAspect {

    @Around("@annotation(logAnnotation)")
    @SneakyThrows
    public Object around(ProceedingJoinPoint proceedingJoinPoint, LogAnnotation logAnnotation) {
        String className = proceedingJoinPoint.getTarget().getClass().getName();
        String methodName = proceedingJoinPoint.getSignature().getName();
        if (log.isDebugEnabled()) {
            log.debug("[类名]:{},[方法]:{}", className, methodName);
        }
        //不保存日志
        if (!logAnnotation.isSaveRequestParameters()) {
            return proceedingJoinPoint.proceed();
        }
        String value = logAnnotation.title();
        String expression = logAnnotation.expression();
        // 当前表达式存在 SPEL，会覆盖 value 的值
        if (StringUtils.hasText(expression)) {
            // 解析SPEL
            MethodSignature methodSignature = (MethodSignature) proceedingJoinPoint.getSignature();
            EvaluationContext evaluationContext = LogUtil.getContext(proceedingJoinPoint.getArgs(), methodSignature.getMethod());

            try {
                value = LogUtil.getValue(evaluationContext, expression, String.class);
            } catch (Exception e) {
                // SPEL 表达式异常，获取 value 的值
                log.error("@SysLog 解析SPEL {} 异常", expression);
            }
        }

        SysLog operateLogDto = LogUtil.getOperateLogBean();
        operateLogDto.setTitle(value);
        // 业务类型
        Integer operateType = logAnnotation.operateType().getValue();
        operateLogDto.setLogType(operateType);
        //默认正常
        operateLogDto.setStatus(BusinessStatus.SUCCESS.getValue());
        //发送异步日志事件
        Long startTime = System.currentTimeMillis();
        Object obj;
        try {
            obj = proceedingJoinPoint.proceed();
        } catch (Throwable e) {
            operateLogDto.setStatus(BusinessStatus.FAIL.getValue());
            operateLogDto.setException(org.apache.commons.lang3.StringUtils.substring(e.getLocalizedMessage(), 0, 2000));
            throw new BusinessException(e.getLocalizedMessage());
        } finally {
            Long endTime = System.currentTimeMillis();
            operateLogDto.setTime(endTime - startTime);
            //异步保存
            SpringContextHolder.publishEvent(new OperateLogEvent(operateLogDto));
        }
        return obj;
    }
}
